package sdtgraph;
import java.awt.Container;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;

import javax.swing.JApplet;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.JToggleButton;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;


@SuppressWarnings("serial")
public class SDTGraph extends JApplet
{
	private GaussGraph gGraph = null;
	
	private JSlider adjustCriterion = new JSlider(1, 30, 5);
	private JLabel criterionLabel = new JLabel("Criterion: "+criterionValue);
	private JSlider noiseMean = new JSlider(0, 30, 5);
	private JLabel noiseLabel = new JLabel("Noise: ");
	private JSlider signalMean = new JSlider(0, 30, 5);
	private JLabel signalLabel = new JLabel("Signal+Noise: ");
	
	private JToggleButton toggleShowFalseAlarms = new JToggleButton("False Alarms");
	private JToggleButton toggleShowCorrectRejections = new JToggleButton("Correct Rejections");
	private JToggleButton toggleShowMisses = new JToggleButton("Misses");
	private JToggleButton toggleShowHits = new JToggleButton("Hits");
	
	private JLabel showInfoLabel = new JLabel("<html>Click to Highlight</html>");
	
	private JLabel yesSignalLabel = new JLabel("Yes Signal");
	private JLabel noSignalLabel = new JLabel("No Signal");
	private JLabel yesResponseLabel = new JLabel("Yes Response");
	private JTextField yyField = new JTextField("0");
	private JTextField ynField = new JTextField("0");
	private JLabel noResponseLabel = new JLabel("No Response");
	private JTextField nyField = new JTextField("0");
	private JTextField nnField = new JTextField("0");
	
	private JPanel controlPane = new JPanel();
	
	public static double noiseMeanOffset = 0;
	public static double signalMeanOffset = 0;
	
	public static boolean showFalseAlarms = false;
	public static boolean showCorrectRejections = false;
	public static boolean showMisses = false;
	public static boolean showHits = false;
	
	private static double criterionValue = 5;
	private static int criterionPosition = 5;
	private static final double GAUSS_MEAN_MULTIPLIER = 6;
	
	public SDTGraph(int size, double mean, double stdev)
	{
		this.gGraph = new GaussGraph(size, mean, stdev);
	}
	
	public void init()
	{
		Container cp = getContentPane();
		cp.add(gGraph);
		
		//JSlider setup
		adjustCriterion.setSnapToTicks(true);
		adjustCriterion.setPaintTicks(true);
		adjustCriterion.setMinorTickSpacing(1);
		adjustCriterion.addChangeListener(new ChangeListener(){
			public void stateChanged(ChangeEvent e) 
			{
		        //Adjust Criterion
				criterionPosition = adjustCriterion.getValue();
				criterionLabel.setText("Criterion: "+criterionValue);
				force_repaint();
			}
		});
		
		noiseMean.setValue((int)noiseMeanOffset);
		noiseMean.setSnapToTicks(true);
		noiseMean.setPaintTicks(true);
		noiseMean.setMinorTickSpacing(1);
		noiseMean.addChangeListener(new ChangeListener(){
			public void stateChanged(ChangeEvent e) 
			{
		        //Adjust Noise Mean
				noiseLabel.setText("Noise: ");
				noiseMeanOffset = GAUSS_MEAN_MULTIPLIER*noiseMean.getValue();
				force_repaint();
			}
		});
		
		signalMean.setValue((int)signalMeanOffset);
		signalMean.setSnapToTicks(true);
		signalMean.setPaintTicks(true);
		signalMean.setMinorTickSpacing(1);
		signalMean.addChangeListener(new ChangeListener(){
			public void stateChanged(ChangeEvent e) 
			{
		        //Adjust Signal Mean
				signalLabel.setText("Signal+Noise: ");
				signalMeanOffset = GAUSS_MEAN_MULTIPLIER*signalMean.getValue();
				force_repaint();
			}
		});
		
		toggleShowFalseAlarms.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e)
			{
				//Show False Alarms Toggle
				showFalseAlarms = toggleShowFalseAlarms.isSelected();
				force_repaint();
			}
		});
		toggleShowFalseAlarms.setForeground(GaussGraph.FALSE_ALARM_COLOR);
		
		toggleShowCorrectRejections.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e)
			{
				//Show Correct Rejections Toggle
				showCorrectRejections = toggleShowCorrectRejections.isSelected();
				force_repaint();
			}
		});
		toggleShowCorrectRejections.setForeground(GaussGraph.CORRECT_REJECTIONS_COLOR);
		
		toggleShowMisses.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e)
			{
				//Show Misses
				showMisses = toggleShowMisses.isSelected();
				force_repaint();
			}
		});
		toggleShowMisses.setForeground(GaussGraph.MISSES_COLOR);
		
		toggleShowHits.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e)
			{
				//Show Misses
				showHits = toggleShowHits.isSelected();
				force_repaint();
			}
		});
		toggleShowHits.setForeground(GaussGraph.HITS_COLOR);
		
		//Set Table Label/Field Orientation
		yesSignalLabel.setHorizontalAlignment(JTextField.CENTER);
		noSignalLabel.setHorizontalAlignment(JTextField.CENTER);
		yesResponseLabel.setHorizontalAlignment(JTextField.CENTER);
		yyField.setHorizontalAlignment(JTextField.CENTER);
		ynField.setHorizontalAlignment(JTextField.CENTER);
		noResponseLabel.setHorizontalAlignment(JTextField.CENTER);
		nyField.setHorizontalAlignment(JTextField.CENTER);
		nnField.setHorizontalAlignment(JTextField.CENTER);
		
		//Text Field Color
		yyField.setForeground(GaussGraph.HITS_COLOR);
		ynField.setForeground(GaussGraph.FALSE_ALARM_COLOR);
		nnField.setForeground(GaussGraph.CORRECT_REJECTIONS_COLOR);
		nyField.setForeground(GaussGraph.MISSES_COLOR);
		
		//TODO Text Field Protection
		yyField.setEditable(false);
		ynField.setEditable(false);
		nnField.setEditable(false);
		nyField.setEditable(false);
		
		//JPanel Control Setup
		controlPane.setOpaque(true);
		controlPane.setLayout(new GridBagLayout());
		GridBagConstraints c = new GridBagConstraints();
		
		c.fill = GridBagConstraints.HORIZONTAL;
		c.gridwidth = 1;
		c.gridheight = 1;
		c.gridx = 0;
		c.gridy = 0;
		controlPane.add(criterionLabel, c);
		
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 0.5;
		c.gridwidth = 2;
		c.gridheight = 1;
		c.gridx = 1;
		c.gridy = 0;
		controlPane.add(adjustCriterion, c);
		
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 0;
		c.gridwidth = 1;
		c.gridheight = 1;
		c.gridx = 0;
		c.gridy = 1;
		controlPane.add(noiseLabel, c);
		
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 0.5;
		c.gridwidth = 2;
		c.gridheight = 1;
		c.gridx = 1;
		c.gridy = 1;
		controlPane.add(noiseMean, c);
		
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 0;
		c.gridwidth = 1;
		c.gridheight = 1;
		c.gridx = 0;
		c.gridy = 2;
		controlPane.add(signalLabel, c);
		
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 0.5;
		c.gridwidth = 2;
		c.gridheight = 1;
		c.gridx = 1;
		c.gridy = 2;
		controlPane.add(signalMean, c);
		
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 0;
		c.gridwidth = 1;
		c.gridheight = 2;
		c.gridx = 0;
		c.gridy = 3;
		controlPane.add(showInfoLabel, c);
		
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 0;
		c.gridwidth = 1;
		c.gridheight = 1;
		c.gridx = 1;
		c.gridy = 3;
		controlPane.add(toggleShowHits, c);
		
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 0;
		c.gridwidth = 1;
		c.gridheight = 1;
		c.gridx = 2;
		c.gridy = 3;
		controlPane.add(toggleShowFalseAlarms, c);
		
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 0;
		c.gridwidth = 1;
		c.gridheight = 1;
		c.gridx = 1;
		c.gridy = 4;
		controlPane.add(toggleShowMisses, c);
		
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 0;
		c.gridwidth = 1;
		c.gridheight = 1;
		c.gridx = 2;
		c.gridy = 4;
		controlPane.add(toggleShowCorrectRejections, c);
		
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 0;
		c.gridwidth = 1;
		c.gridheight = 1;
		c.gridx = 1;
		c.gridy = 5;	
		controlPane.add(yesSignalLabel, c); 
		
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 0;
		c.gridwidth = 1;
		c.gridheight = 1;
		c.gridx = 2;
		c.gridy = 5;
		controlPane.add(noSignalLabel, c);
		
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 0;
		c.gridwidth = 1;
		c.gridheight = 1;
		c.gridx = 0;
		c.gridy = 6;
		controlPane.add(yesResponseLabel, c);
		
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 0;
		c.gridwidth = 1;
		c.gridheight = 1;
		c.gridx = 1;
		c.gridy = 6;
		controlPane.add(yyField, c);
		
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 0;
		c.gridwidth = 1;
		c.gridheight = 1;
		c.gridx = 2;
		c.gridy = 6;
		controlPane.add(ynField, c);
		
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 0;
		c.gridwidth = 1;
		c.gridheight = 1;
		c.gridx = 0;
		c.gridy = 7;
		controlPane.add(noResponseLabel, c);
		
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 0;
		c.gridwidth = 1;
		c.gridheight = 1;
		c.gridx = 1;
		c.gridy = 7;
		controlPane.add(nyField, c);
		
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 0;
		c.gridwidth = 1;
		c.gridheight = 1;
		c.gridx = 2;
		c.gridy = 7;
		controlPane.add(nnField, c);
		
		cp.add("South", controlPane);
		
		criterionValue = adjustCriterion.getValue();
	}
	
	public void updateTable()
	{
		this.yyField.setText(""+Math.round(GaussGraph.yyCount));
		this.ynField.setText(""+Math.round(GaussGraph.ynCount));
		this.nyField.setText(""+Math.round(GaussGraph.nyCount));
		this.nnField.setText(""+Math.round(GaussGraph.nnCount));
	}
	
	private void updateCriterion()
	{
		//Criterion = Y/N
		double yesCount = Double.parseDouble(this.yyField.getText()) 
			+ Double.parseDouble(this.ynField.getText());
		
		double noCount = Double.parseDouble(this.nnField.getText()) +
			+ Double.parseDouble(this.nyField.getText());
		
		criterionValue = roundTwoDecimals(yesCount/noCount);
	}
	
	public void force_repaint()
	{
		updateTable(); updateCriterion();
		this.validate(); this.repaint();
		//controlPane.validate(); controlPane.repaint();
		gGraph.validate(); gGraph.repaint();
		updateTable(); updateCriterion();
		
	}
	
	public static int getCriterionPosition()
	{
		return criterionPosition;
	}
	
	public static double roundTwoDecimals(double d) 
	{
        DecimalFormat twoDForm = new DecimalFormat("#.##");
        return Double.valueOf(twoDForm.format(d));
	}
}
